/**
 * 
 */
package vin.echo.core;

import java.lang.reflect.Field;
import java.util.HashMap;

import vin.echo.core.annotation.InjectModule;
import vin.echo.core.exception.ClassLoopInjectException;
import vin.echo.core.exception.EchoBuildExeception;
import vin.echo.core.exception.ParamenterException;

/**
 * @author Vin.Ma
 * 
 */
public class RelationAdapter {

	private HashMap<String, Field> adapterMap;

	private ServiceContext context;

	public RelationAdapter(ServiceContext context) {
		adapterMap = new HashMap<String, Field>();
		this.context = context;
	}

	public void adapte(Class<?> claz) throws ClassLoopInjectException {
		Field[] fs = claz.getDeclaredFields();
		for (Field f : fs) {
			f.setAccessible(true);
			if (isInjectModule(f)) {
				Class<?> targetClass = f.getType();
				hasLoopInject(claz, targetClass);
				String fieldName = ContextUtils.getFiledKey(claz, f);
				adapterMap.put(fieldName, f);

			}
		}
	}

	public void hasLoopInject(Class<?> source, Class<?> target)
			throws ClassLoopInjectException {
		Field[] fs = target.getDeclaredFields();
		for (Field f : fs) {
			if (f.getType().equals(source)) {
				throw new ClassLoopInjectException();
			}
		}
	}

	public void buildObject(Object o) throws ParamenterException,
			EchoBuildExeception {
		Class<?> claz = o.getClass();
		for (Field f : claz.getDeclaredFields()) {
			if (isInjectModule(f)) {
				fillField(o, f);
			}
		}
	}

	private void fillField(Object o, Field f) throws EchoBuildExeception,
			ParamenterException {
		f.setAccessible(true);

		String name = ContextUtils.getServiceName(f.getType());
		EchoService service = context.getService(name);

		try {
			f.set(o, service);
		} catch (Exception e) {
			throw new EchoBuildExeception();
		}
	}

	private boolean isInjectModule(Field f) {
		InjectModule imDesc = f.getAnnotation(InjectModule.class);
		return imDesc != null;
	}

}
